<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- <script src="http://unpkg.com/vue@next"></script> -->

</head>

<body>
    <div id="app">
        <h1>{{title}}</h1>
    </div>

    <script>
        const Vue = {
            creatRenderer({
                querySelector,
                insert
            }) {
                return {
                    createApp(options) {
                        return {
                            mount(selector) {
                                //console.log('mount');
                                const parent = document.querySelector(selector);

                                if (!options.render) {
                                    options.render = this.compile(parent.innerHTML);
                                }

                                if (!options.setup) {
                                    this.setupState = options.setup();
                                }

                                if (!options.data) {
                                    this.data = options.data();
                                }

                                const proxy = new Proxy(this, {
                                    get(target, key) {
                                        if (target.setupState && key in target.setupState) {
                                            return Reflect.get(target.setupState, key);
                                        } else {
                                            return Reflect.get(target.data, key);
                                        }
                                    },

                                    set(target, key, val) {
                                        if (target.setupState && key in target.setupState) {
                                            Reflect.set(target.setupState, key, val);
                                        } else {
                                            Reflect.set(target.data, key, val);
                                        }
                                        app.update();
                                    }
                                })

                                // const el = options.render.call(options.data());
                                const el = options.render.call(proxy);

                                // parent.appendChild(el);
                                insert(el, parent);
                            },

                            compile(template) {
                                return function render() {
                                    const h3 = document.createElement('h3');
                                    h3.textContent = this.title;
                                    return h3;
                                }
                            }
                        }
                    }
                }

            },
            createApp(options) {
                const renderer = Vue.createRenderer({
                    querySelector(sel) {
                        return document.querySelector(sel);
                    },
                    insert(el, parent) {
                        parent.innerHTML = '';
                        parent.appendChild(el);
                    }
                })
                return renderer.creaeApp(options);
            }
        }
    </script>

    <script>
        // 拦截用户对代理对象的访问，在值变化时响应
        function reactive(obj) {
            // vue2
            // Object.defineProperty(obj, {})
            return new Proxy(obj, {
                get(target, key) {
                    console.log('get key', key);
                    return Reflect.get(target, key);
                    // return target[key]
                },
                set(target, key, val) {
                    console.log('set');
                    // target[key] = val
                    Reflect.set(target, key, val);
                    app.update()
                }
            })

        }
    </script>
    <script>
        const app = Vue.createApp({
            // data() {
            //   return {
            //     title: 'Hello, vue3 :)'
            //   }
            // },
            
            setup() {
                const state = reactive({
                    title: 'Vue3 hello! XD'
                })
                setTimeout(() => {
                    state.title = '2s后 :)'
                }, 2000)

                return state;
            }
        })

        app.mount('#app'); 
    </script>

</body>

</html>